import os, json, sys, time, subprocess, copy, logging
import serial

logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', level=logging.DEBUG, datefmt='%Y/%m/%d %H:%M:%S')

class EspMouse(object):
    port = ''
    model = ''
    serialDelay = 0.02
    btv = 115200
    #isTest主要用来测试输出是否正确的,只打印,但不会向串口发送任何数据
    def __init__(self, port, model,isTest = False):
        self.cmdTest = isTest
        self.port = port
        self.model = model
        self.serial = None
        self.name = 'test'
        if not self.cmdTest:
            self.serial = serial.Serial(self.port,self.btv,timeout=1)
            self.name = self.get_name()
        logging.info(f'EspMouse() name={self.name}, port={self.port}, model={self.model}')

    def get_name(self):
        name = self.sendAndRead('*')
        return name.strip().split(",")[0]

# 格式: [9个Bytes]
#   B1    B2 B3                     B4 B5        B6     B7     B8,B9
#   抬起   x方向 (-126-126) & 速度    y..          滚轮x  滚轮y   无用
#   00    0f 01                     00 00        00     00     0000

# 问题1,  连接一段时间后, 设备与苹果手机断开连接, 蓝牙设备里点击连接无效, 需要对设备断电再插上电脑

# 问题2,  向右移动10,再向左移动10, 成功回到原点. 但是接下来的点击命令, 造成了意外的鼠标移动
#   问题原因 - 以下点击/抬起操作,似乎会重复最后一次移动命令 也就是向左移10
#   readcom = 010000000000000000 点击 
#   readcom = 000000000000000000 抬起

    def test_move(self):
        self.sendAndRead('[00' + '0a' + '09' + '00' + '00'+ '00' + '00' + '0000]')  # 向右移动10)
        self.sendAndRead('[00' + '0a' + '09' + '00' + '00'+ '00' + '00' + '0000]') # 向右移动10
        self.sendAndRead('[00' + 'f6' + '09' + '00' + '00'+ '00' + '00' + '0000]') # 向左移动10 
        self.sendAndRead('[00' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') # 向左移动10 

    def click_checkbox(self):
        #self.sendAndRead('[00' + '00' + '00' + '7e' + '10'+ '00' + '00' + '0000]') #  y +126 up 
        #self.sendAndRead('[00' + '7e' + '10' + '00' + '00'+ '00' + '00' + '0000]') #  x +126 up 

        #self.sendAndRead('[00' + '7e' + 'ff' + '00' + '00'+ '00' + '00' + '0000]') # x +126
        self.sendAndRead('[00' + '00' + '00' + '82' + '10'+ '00' + '00' + '0000]') #  y -126 up 
        self.sendAndRead('[00' + '82' + '10' + '00' + '00'+ '00' + '00' + '0000]') #  x -126 up 
        self.sendAndRead('[00' + '00' + '00' + '11' + 'e0'+ '00' + '00' + '0000]') #  y +17 up 
        self.sendAndRead('[00' + '0b' + '01' + '00' + '00'+ '00' + '00' + '0000]') #  x +5 up 
        self.sendAndRead('[01' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') #  click
        self.sendAndRead('[00' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') #  up
    def int_to_8hexstr(self,n):
        hex8str = hex(n & 0xFF)[2:]  # 使用32位二进制表示，去掉前面的"0x"
        return hex8str.zfill(2)
    def move(self,mtype = 0,xmax = 0,xstep = 0,ymax = 0,ystep = 0,hmax = 0,hstep = 0,wmax= 0,wstep = 0):
        p1 = self.int_to_8hexstr(mtype)
        p2 = self.int_to_8hexstr(xmax)
        p3 = self.int_to_8hexstr(xstep)
        p4 = self.int_to_8hexstr(ymax)
        p5 = self.int_to_8hexstr(ystep)
        p6 = self.int_to_8hexstr(hmax)
        p7 = self.int_to_8hexstr(hstep)
        p8 = self.int_to_8hexstr(wmax)
        p9 = self.int_to_8hexstr(wstep)
        out = '[' + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 +']'
        return out
    def moveDelayTime(self,mmax,step):
        t = abs(mmax)*2*0.01 + step*0.01
        print('delay time:%03f'%(t))
        time.sleep(t)
    def click(self):
        tdowncmd = self.move(mtype = 1)
        self.sendAndRead(tdowncmd)
        time.sleep(0.05)
        tupcmd = self.move()
        self.sendAndRead(tupcmd)
    def moveX(self,xmax,xstep,mtype = 0):
        mcmd = self.move(mtype = mtype,xmax = xmax,xstep = xstep)
        self.sendAndRead(mcmd)
        self.moveDelayTime(xmax, xstep)
    def moveY(self,ymax,ystep,mtype = 0):
        mcmd = self.move(mtype = mtype,ymax = ymax,ystep = ystep)
        self.sendAndRead(mcmd)
        self.moveDelayTime(ymax, ystep)

    def moveH(self,hmax,hstep):
        mcmd = self.move(hmax = hmax,hstep = hstep)
        self.sendAndRead(mcmd)
        self.moveDelayTime(hmax, hstep)

    def moveW(self,wmax,wstep):
        mcmd = self.move(wmax = wmax,wstep = wstep)
        self.sendAndRead(mcmd)
        self.moveDelayTime(wmax, wstep)

    def clear_history(self):
        # 滚轮往下拉到底  
        # 问题1. 有时不起作用 - 问题见视频
        # 问题2. 这里是往下移动, 但是发的指令是 滚轮 x? 
        # self.sendAndRead('[00' + '00' + '00' + '00' + '00'+ '01' + '19' + '0000]')  
        self.moveH(1,25)

        # 鼠标移到最左上角
        # self.sendAndRead('[00' + '82' + '10' + '00' + '00'+ '00' + '00' + '0000]') #  x -126 
        self.moveX(-1,120)
        
        # self.sendAndRead('[00' + '00' + '00' + '82' + '10'+ '00' + '00' + '0000]') #  y -126 
        self.moveY(-1,120)
        
        # 鼠标⬇️16
        # self.sendAndRead('[00' + '00' + '00' + '12' + 'e0'+ '00' + '00' + '0000]') #  y +16
        self.moveY(1,16)

        # 点蓝色 "清除浏览记录"
        # self.sendAndRead('[01' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') #  click 清除历史记录
        self.click()

        # 鼠标⬇️32
        # self.sendAndRead('[00' + '00' + '00' + '18' + '00'+ '00' + '00' + '0000]') #  y +32 底部 红色 清除历史记录与数据
        self.moveY(1,32)
        print("sleep 5")
        time.sleep(5.5)
        # 点底部的红色 "清除浏览记录", 测试结果看起来是发了键盘 tab / ⬇️, 问题见视频
        # self.sendAndRead('[01' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') #  click
        self.click()

        # 点"关闭标签"
        time.sleep(2)
        # self.sendAndRead('[01' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') #  click 关闭标签
        self.click()
        #self.sendAndRead('[00' + '00' + '00' + '00' + '00'+ '00' + '00' + '0000]') # 向左移动10 
        self.moveX(-1,10)

    def sendAndRead(self, cmd):
        # sendAndread
        print('send:',cmd)
        if self.cmdTest:
            return
        self.serial.write(cmd.encode())
        self.serial.flush()
        time.sleep(self.serialDelay)

        # readcom
        n = self.serial.inWaiting()
        while n<=0:
            time.sleep(self.serialDelay)
            n = self.serial.inWaiting()
        pstr = self.serial.read(n).decode()
        print(pstr)
        return pstr # print(f'readcom = {pstr}')


def main():
    import argparse
    parser = argparse.ArgumentParser(description='port')
    parser.add_argument('--port', required=True)
    parser.add_argument('--action', required=True)
    args = vars(parser.parse_args())

    espmouse = EspMouse(port=args['port'],model='13PM')

    if args['action'] == 'move':
        espmouse.test_move()
    elif args['action'] == 'click':
        espmouse.click_checkbox()
    elif args['action'] == 'history':
        espmouse.clear_history()
    else:
        logging.error("unknow action")
    time.sleep(3)

def test():
    import argparse
    parser = argparse.ArgumentParser(description='port')
    parser.add_argument('--port', required=True)
    parser.add_argument('--action', required=True)
    args = vars(parser.parse_args())
    espmouse = EspMouse(port=args['port'],model='13PM',isTest = True)
    espmouse.clear_history()
# 运行方法: python3 espmouse.py --port=/dev/tty.usbserial-14140 --action=history
if __name__ == '__main__':
    # test()
    main()
    #espmouse.test_move()